Package ru.dubov.convexhull

Source Code of ru.dubov.convexhull.ConvexHull$PointComparator

package ru.dubov.convexhull;

import java.util.*;
import ru.dubov.primitives.Point;
import ru.dubov.primitives.Polygon;

/**
* Builds the convex hull of a given set of points
* using different algorithms.
*
* @author Mikhail Dubov
*/
public class ConvexHull {
   
    /**
     * Builds the convex hull of a given set of points
     * using the Graham's scan algorithm - O(n*log(n)).
     */
    public static Polygon Graham(ArrayList<Point> pointsList) {
       
        // Список точек будет меняться (предполагаем, что pointsList.size >= 3)
       
        ArrayList<Point> points = (ArrayList<Point>)pointsList.clone();
        Stack<Point> result = new Stack<Point>();
       
        // Получаем нижнюю левую точку - первую вершину оболочки - O(n)
       
        Point p0 = getLowestPoint(points);
        result.push(p0);
        points.remove(p0);
       
        // Оставшиеся вершины сортируем по возрастанию полярного угла - O(n*log(n))
       
        Collections.sort(points, new PointComparator(p0));
       
        // Перед началом сканирования заносим еще две точки в стек
       
        Iterator<Point> iter = points.iterator();
       
        Point p1 = iter.next();
        result.push(p1);
       
        Point p2 = iter.next();
        result.push(p2);
       
        // Совершаем проход по отсортированному списку,
        // определяя, какие вершины входят в оболочку - O(n)
       
        while (iter.hasNext()) {
            Point pi = iter.next();
            Point top = result.elementAt(result.size() - 1);
            Point nextToTop = result.elementAt(result.size() - 2);
           
            while (! isLeftTurn(nextToTop, top, pi)) {
                result.pop();
               
                // Не забываем обновить
                top = nextToTop;
                nextToTop = result.elementAt(result.size() - 2);
            }
           
            result.push(pi);
        }
       
        // Оболочка построена, возвращаем список точек
        // в порядке обхода против часовой стрелки
       
        ArrayList<Point> polygon = new ArrayList<Point>();
        while(! result.empty()) {
            polygon.add(result.pop());
        }
        Collections.reverse(polygon);
       
        return new Polygon(polygon);
    }
   
    /**
     * Builds the convex hull of a given set of points
     * using the Jarvis' march algorithm - O(n*h),
     * where h is the number of vertises in the hull,
     * so the worst case is O(n^2).
     */
    public static Polygon Jarvis(ArrayList<Point> pointsList) {
       
        // Список точек будет меняться (предполагаем, что pointsList.size >= 3)
       
        ArrayList<Point> points = (ArrayList<Point>)pointsList.clone();
        ArrayList<Point> result = new ArrayList<Point>();
       
        // Получаем нижнюю левую точку - первую вершину оболочки - O(n)
       
        Point p0 = getLowestPoint(points);
        result.add(p0);
        points.remove(p0);
       
        // Получаем последнюю вершину оболочки - O(n)
       
        Point pE = points.get(0);
        Point candidate;
        for(int i = 1; i < points.size(); i++) {
            candidate = points.get(i);
            if(crossProduct(p0, candidate, pE) < 0) {
                pE = candidate;
            }
        }
       
        // Строим цепь - O(h) шагов...
       
        Point next = null;
        Point last = p0;
        do {
            // ... на каждом - перебор O(n) точек, итого O(n*h) операций
            next = points.get(0);
           
            for(int i = 1; i < points.size(); i++) {
                candidate = points.get(i);
                if (crossProduct(last, candidate, next) > 0 ||
                        crossProduct(last, candidate, next) == 0 &&
                        last.dist(candidate) > last.dist(next)) {
                    next = candidate;
                }
            }
           
            result.add(next);
            points.remove(next);
            last = next;
           
        } while(next != pE);
       
        // Оболочка построена, возвращается список точек
        // в порядке обхода против часовой стрелки
       
        return new Polygon(result);
    }
   
    /**
     * Compares two points by their polar angles
     * using the cross product.
     */
    static class PointComparator implements Comparator<Point> {
       
        private Point p0;
       
        public PointComparator(Point p0) {
            this.p0 = p0;
        }
       
        // Сравнение точек по их полярному углу относительно p0;
        // если совпадает - то по удаленности от p0.
        @Override
        public int compare(Point p1, Point p2) {
           
            double crossProduct = crossProduct(p0, p1, p2);
           
            if (crossProduct > 0) return -1;
            if (crossProduct < 0) return 1;
           
            // cross_product = 0, векторы коллинеарны -> нужен тот, что дальше
            double d1 = p0.dist(p1);
            double d2 = p0.dist(p2);
           
            if (d1 < d2) return -1;
            if (d1 > d2) return 1;
           
            return 0;
        }
    }
   
    private static double crossProduct(Point p0, Point p1, Point p2) {
        return (p1.getX() - p0.getX()) * (p2.getY() - p0.getY()) -
                (p2.getX() - p0.getX()) * (p1.getY() - p0.getY());
    }
   
    private static boolean isLeftTurn(Point p0, Point p1, Point p2) {
        return (crossProduct(p0, p1, p2) > 0);
    }
   
    private static Point getLowestPoint(ArrayList<Point> points) {
        Point result = points.get(0);
       
        Point candidate;
        for (int i = 1; i < points.size(); i++) {
            candidate = points.get(i);
           
            if (candidate.getY() < result.getY() ||
                    candidate.getY() == result.getY() && candidate.getX() < result.getX()) {
                result = candidate;
            }
        }
       
        return result;
    }
   
    private static void printPointsList(ArrayList<Point> points) {
        for (Point p : points) {
            System.out.println(p);
        }
    }
}
TOP

Related Classes of ru.dubov.convexhull.ConvexHull$PointComparator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.